﻿using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Basedatas.Customers;
using mozhi.smarterp.Finance.Basedatas.Events;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;

namespace mozhi.smarterp.Finance.Basedatas
{
    public class CustomerAppService : BaseDataAppService<Customer , CustomerDto , CustomerCreateDto , CustomerUpdateDto>, ICustomerAppService
    {
        private IAccountRepository _accountRepository;
        public CustomerAppService(IAccountRepository accountRepository,IServiceProvider serviceProvider)
            : base(serviceProvider , ModuleCodeType.Customer)
        {
            _accountRepository = accountRepository;
        }

        public override async Task<PagedResultDto<CustomerDto>> FindAsync(PageQuery query)
        {
            var result = await base.FindAsync(query);

            var customers = result.Items;
            if (customers.Count == 0)
                return result;

            //加载科目信息
            await LoadAccountInfoAsync(customers.ToList());

            return result;
        }

        public override async Task<CustomerDto> CreateAsync(CustomerCreateDto dto)
        {
            await Validate(null, dto.Code, dto.Name);

            await ValidateAccount(dto.ReceivableAccountId, dto.PrereceiveAccountId);

            var customer = new Customer(_guidGenerator.Create(), dto.Code, dto.Name , dto.ReceivableAccountId , dto.PrereceiveAccountId , dto.Activated);

            customer = await _repository.InsertAsync(customer);

            await _operationLogManager.LogAsync(ModuleCodeType.Customer, OperationType.Add, customer, null);

            var result = ObjectMapper.Map<Customer, CustomerDto>(customer);

            await LoadAccountInfoAsync(new List<CustomerDto>() { result });

            return result;
        }

        public async override Task<CustomerDto> UpdateAsync(CustomerUpdateDto dto)
        {
            var customer = await _repository.GetAsync(dto.Id);

            if (customer == null)
                throw new UserFriendlyException("客户不存在", "100000");

            var oldCustomer = ObjectMapper.Map<Customer, CustomerDto>(customer);

            await Validate(dto.Id, dto.Code, dto.Name);

            await ValidateAccount(dto.ReceivableAccountId, dto.PrereceiveAccountId);

            customer.Change(dto.Code, dto.Name, dto.Activated);
            customer.ChangeAccount(dto.ReceivableAccountId ,dto.PrereceiveAccountId);

            customer = await _repository.UpdateAsync(customer);

            var result = ObjectMapper.Map<Customer, CustomerDto>(customer);

            await LoadAccountInfoAsync(new List<CustomerDto>() { result });

            await _operationLogManager.LogAsync(ModuleCodeType.Customer, OperationType.Update, oldCustomer, result);

            return result;
        }

        public override async Task<CustomerDto> DeleteAsync(Guid id)
        {
            var customer = await base.DeleteAsync(id);

            await _distributedEventBus.PublishAsync(new DataAssociationRemoveEvent(id, customer.ReceivableAccountId));
            await _distributedEventBus.PublishAsync(new DataAssociationRemoveEvent(id, customer.PrereceiveAccountId));

            return customer;
        }


        #region
        private async Task LoadAccountInfoAsync(List<CustomerDto> customers)
        {
            var accountIds = customers.Where(x => x.ReceivableAccountId != default).Select(x => x.ReceivableAccountId).ToList();

            accountIds.AddRange(customers.Where(x => x.PrereceiveAccountId != default).Select(x => x.PrereceiveAccountId).ToList());

            accountIds = accountIds.Distinct().ToList();

            if (accountIds.Count == 0)
                return;

            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = accountIds });


            foreach (var customer in customers)
            {
                customer.ReceiveableAccountName = accounts.FirstOrDefault(x => x.Id == customer.ReceivableAccountId)?.FullName;
                customer.PrereceiveAccountName = accounts.FirstOrDefault(x => x.Id == customer.PrereceiveAccountId)?.FullName;
            }
        }


        private async Task ValidateAccount(Guid receivableAccountId, Guid prereceiveAccountId)
        {
            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = new List<Guid> { receivableAccountId , prereceiveAccountId } });

            var matchReceivableAccount = accounts.FirstOrDefault(x=>x.Id == receivableAccountId);

            base.ValidateAccount(matchReceivableAccount, "应收科目");

            var matchPrereceiveAccount = accounts.FirstOrDefault(x => x.Id == prereceiveAccountId);

            base.ValidateAccount(matchPrereceiveAccount, "应收科目");
        }
        #endregion
    }
}
